// 条件类型

// 如果不使用条件类型，则是将整个联合类型拿去比较。
type NoType = string | number | boolean extends string | number ? string : never  // never，boolean类型无法兼容string和number

// ### 分布式条件类型
// 泛型中的联合类型，是一个一个传进入，循环进行校验的
type Example<T> = T extends string | number ? T : never
type IdType = Example<string | number | boolean>  // string | boolean

// ### 类型推断
// 结合infer类型推断，可以在条件类型中提取局部变量
class Subject { constructor(public subName: string, public subScore: number) {} }
let chineseSub = new Subject("语文", 60)
let allSub = new Set([chineseSub])

type ConstructorSub<T> = T extends Set<infer U> ? U : never
type SubCopy = ConstructorSub<typeof allSub>  // type SubCopy = Subject

// ### 递归与嵌套
// 条件类型可以嵌套，或递归使用，实现复杂类型逻辑（类型体操）。
type Flatter<T> = T extends Array<infer U> ? Flatter<U> : T
type NestedArr = Flatter<number[][][]>  // number

// ### 作业： 向原有接口中，添加属性
interface Customer { name: string; age: number }

type AddAttrToObj<T, K extends string, V> = {  // 接口和类是不能作为属性名的，要做约束
  // 错误，属性名里，已经推断出T是对象。P既然extends了T，那P也是对象。父对象[子对象]的写法是错误的
  // [P in keyof T | K]: P extends T ? T[P] : V
  // P extends keyof T，证明 P 可能是 T 的属性名，写法正确
  [P in keyof T | K]: P extends keyof T ? T[P] : V
}
type CustomerNew = AddAttrToObj<Customer, "address", string>  // { address: string; name: string; age: number; }
export {}